#include <iostream>
#include <vector>
#include <cassert>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

static const int gmax = 10;

template<class T>
class RingQueue
{
public:
    RingQueue(const int &cap = gmax)
        :_q(cap)
        ,_cap(cap)
    {
        int n = sem_init(&_spacesem, 0, _cap);
        assert(0 == n);
        n = sem_init(&_datasem, 0, 0);
        assert(0 == n);

        _productor_index = _consumer_index = 0;

        pthread_mutex_init(&_plock, nullptr);
        assert(0 == n);
        n = pthread_mutex_init(&_clock, nullptr);
        assert(0 == n);
    }

    ~RingQueue()
    {
        sem_destroy(&_spacesem);
        sem_destroy(&_datasem);

        pthread_mutex_destroy(&_plock);
        pthread_mutex_destroy(&_clock);
    }

    void Push(const T &in)
    {
        // 申请信号量
        P(_spacesem);

        pthread_mutex_lock(&_plock);
        _q[_productor_index++] = in;
        _productor_index %= _cap;
        pthread_mutex_unlock(&_plock);

        // 归还信号量
        V(_datasem);
    }

    void Pop(T *out)
    {
        // 申请信号量
        P(_datasem);

        pthread_mutex_lock(&_clock);
        *out = _q[_consumer_index++];
        _consumer_index %= _cap;
        pthread_mutex_unlock(&_clock);

        // 归还信号量
        V(_spacesem);
    }

private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

private:
    vector<T> _q;
    int _cap;
    sem_t _spacesem;
    sem_t _datasem;
    int _productor_index;
    int _consumer_index;
    pthread_mutex_t _plock;
    pthread_mutex_t _clock;
};
